import * as parser from "@babel/parser";
import traverse from "@babel/traverse";
import doctrine from "doctrine";
import fs from "node:fs";

function resolveType(tsType) {
  const typeAnnotation = tsType.typeAnnotation;
  if (!typeAnnotation) {
    return "any";
  }
  switch (typeAnnotation.type) {
    case "TSStringKeyword":
      return "string";
    case "TSNumberKeyword":
      return "number";
    case "TSBooleanKeyword":
      return "boolean";
  }
}

function parseComment(commentStr) {
  if (!commentStr) {
    return;
  }
  return doctrine.parse(commentStr, {
    unwrap: true,
  });
}

function generateDoc(docs) {
  let str = "";

  docs.forEach((doc) => {
    if (doc.type === "function") {
      str += "## " + doc.name + "\n \n";
      str += doc.doc.description + "\n \n";
      if (doc.doc.tags) {
        doc.doc.tags.forEach((tag) => {
          str += "123" + tag.name + ": " + tag.description + "\n \n";
        });
      }
      str += ">" + doc.name + "(";
      if (doc.params) {
        str += doc.params
          .map((param) => {
            return param.name + ": " + param.type;
          })
          .join("\n \n");
      }
      str += ")\n \n";
      str += "#### Parameters: \n \n";
      if (doc.params) {
        str += doc.params
          .map((param) => {
            return "-" + param.name + "(" + param.type + ")";
          })
          .join("\n");
      }
      str += "\n";
    }
    str += "\n";
  });
  return str;
}

export default function docGenerate() {
  const docs = [];
  return {
    name: "docGenerate",
    async transform(code) {
      const sourceCode = code;
      const babelParsedAst = parser.parse(sourceCode, {
        sourceType: "unambiguous",
      });
      traverse.default(babelParsedAst, {
        ExportNamedDeclaration(path) {
          const funcDeclaration = path.get("declaration");
          docs.push({
            type: "function",
            name: funcDeclaration.get("id").toString(),
            params: funcDeclaration.get("params").map((paramPath) => {
              return {
                name: paramPath.toString(),
                type: resolveType(paramPath.getTypeAnnotation()),
              };
            }),
            return: resolveType(
              funcDeclaration.get("returnType").getTypeAnnotation()
            ),
            doc:
              path.node.leadingComments &&
              parseComment(path.node.leadingComments[0].value),
          });
        },
      });
      return {
        code,
        map: null,
      };
    },
    writeBundle() {
      fs.writeFile("./文档.md", generateDoc(docs), function (err) {
        if (err) {
          return console.log("文件写入失败！" + err.message);
        }
        console.log("文件写入成功！");
      });
    },
  };
}


